package com.zhuoyue.biz.core.api.service.impl;

import java.util.*;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.zhuoyue.biz.core.api.dao.DeviceDao;
import com.zhuoyue.biz.core.api.dao.GatewayDao;
import com.zhuoyue.biz.core.api.dao.InfraredDeviceActionsMapper;
import com.zhuoyue.biz.core.api.domain.GatewayDO;
import com.zhuoyue.biz.core.api.domain.InfraredDeviceActions;
import com.zhuoyue.biz.core.api.dto.rep.InfraredDeviceRepDTO;
import com.zhuoyue.biz.core.api.service.impl.ac.AcInfraredAction;
import com.zhuoyue.common.exception.ErrorType;
import com.zhuoyue.common.exception.ZyServerException;
import lombok.RequiredArgsConstructor;
import net.sf.json.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zhuoyue.biz.core.api.dao.InfraredDeviceDao;
import com.zhuoyue.biz.core.api.domain.InfraredDeviceDO;
import com.zhuoyue.biz.core.api.service.InfraredDeviceService;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author wjming
 * @ClassName: InfraredDeviceServiceImpl
 * @Description: 红外设备服务
 * @Date 2021-07-08 9:20
 */
@Service("infraredDeviceService")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class InfraredDeviceServiceImpl extends ServiceImpl<InfraredDeviceDao, InfraredDeviceDO> implements InfraredDeviceService {

    private final InfraredDeviceDao infraredDeviceDao;
    private final InfraredDeviceActionsService infraredDeviceActionsService;
    private final ProductInfoAppService productInfoAppService;
    private final DeviceDao deviceDao;
    private final GatewayDao gatewayDao;

    /**
     * 获取红外设备信息
     * 1、获取该家庭下所有的红外设备信息
     * 2、获取该家庭下空外设备控制器
     * 3、可用与不可用红外设备分类
     * 4、合并红外设备返回给前端
     *
     * @param gatewayDO
     * @return
     */
    @Override
    public List<InfraredDeviceRepDTO> getInfraredDeviceListByGatewayId(GatewayDO gatewayDO) {
        //获取红外设备列表
        List<InfraredDeviceDO> infraredDeviceDoS = infraredDeviceDao.getInfraredList(gatewayDO.getHomeId());

        if (CollectionUtils.isEmpty(infraredDeviceDoS)) {
            return Collections.emptyList();
        }

        //根据网关id找到对应的红外学习仪
        List<String> deviceIds = deviceDao.selectIdByType(gatewayDO.getId());

        List<InfraredDeviceRepDTO> infraredUsable = new ArrayList<>();
        List<InfraredDeviceRepDTO> infraredDisabled = new ArrayList<>();
        for (InfraredDeviceDO infraredDeviceDO : infraredDeviceDoS) {
            List<String> deviceFun = productInfoAppService.getDeviceFun(infraredDeviceDO.getProdId());
            InfraredDeviceRepDTO infraredDeviceRep = new InfraredDeviceRepDTO().doToDto(infraredDeviceDO, deviceFun);
            if (deviceIds.contains(infraredDeviceDO.getDeviceId())) {
                InfraredDeviceActions actions = infraredDeviceActionsService.getOne(Wrappers.<InfraredDeviceActions>lambdaQuery()
                        .eq(InfraredDeviceActions::getInfraredDeviceId, infraredDeviceDO.getId()));
                if (actions != null) {
                    infraredDeviceRep.setActions(actions.getActionsValue());
                }

                infraredUsable.add(infraredDeviceRep);
            } else {
                //预防设备已经删除但是红外设备还没有删除的
                infraredDeviceDO.setName(infraredDeviceDO.getName() + ("不可用"));
                infraredDisabled.add(infraredDeviceRep);
            }
        }
        if (CollectionUtils.isNotEmpty(infraredDisabled)) {
            infraredUsable.addAll(infraredDisabled);
        }
        return infraredUsable;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public InfraredDeviceDO addInfraredDevice(InfraredDeviceDO infraredDevice) {
        int count;
        if (infraredDevice.getRoomId() == null) {
            //插入之前先判断一下是否此空调下有此ID
            String code = infraredDevice.getCentralAcCode();
            List<InfraredDeviceDO> list = infraredDeviceDao.selectInfraredDeviceListByDeviceId(infraredDevice.getDeviceId());
            if (list.size() > 0) {
                for (InfraredDeviceDO infraredDevices : list
                ) {
                    if (StringUtils.isNotEmpty(code) && infraredDevices.getCentralAcCode().equals(code)) {
                        throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "空调码" + code + "已存在");
                    }
                }
            }

            count = infraredDeviceDao.insert(infraredDevice);
            if (count < 1) {
                throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "中央空调设备新增失败！");
            }
        } else {
            count = infraredDeviceDao.insert(infraredDevice);
            if (count < 1) {
                throw new ZyServerException(ErrorType.Service_Fail.getCode(), "红外设备新增失败！");
            }
        }
        return infraredDeviceDao.selectByIdAndRoomName(infraredDevice.getId());
    }


    @Override
    public InfraredDeviceDO updateInfraredDeviceById(InfraredDeviceDO infraredDevice) {
        int count = infraredDeviceDao.updateById(infraredDevice);
        if (count < 1) {
            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "修改失败");
        }
        InfraredDeviceDO infrared = infraredDeviceDao.selectByIdAndRoomName(infraredDevice.getId());
        InfraredDeviceActions actions = infraredDeviceActionsService.getOne(Wrappers.<InfraredDeviceActions>lambdaQuery()
                .eq(InfraredDeviceActions::getInfraredDeviceId, infrared.getId()));
        if (actions != null) {
            infrared.setActions(actions.getActionsValue());
        }
        return infrared;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteInfraredDeviceById(String id) {
        int count = infraredDeviceDao.deleteInfraredDeviceById(id);
        if (count < 1) {
            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "红外设备删除失败");
        }
    }


    @Override
    public List<InfraredDeviceDO> getAirDeviceListByDeviceId(String deviceId) {
        List<InfraredDeviceDO> list = infraredDeviceDao.selectInfraredDeviceListByDeviceId(deviceId);
        if (CollectionUtils.isEmpty(list)) {
            throw new ZyServerException(ErrorType.result_not_exist.getCode(), "查询设备内容为空");
        }
        return list;
    }

    @Override
    public void addAcCenter(String deviceMac, String gatewayMac, Map<String, Object> map) {
        String deviceId = deviceDao.selectDeviceIdByMac(deviceMac);
        String homeId = gatewayDao.selectHomeIdByGatewayMac(gatewayMac);
        if (StringUtils.isEmpty(homeId)) {
            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "0FAC0207中央空调设备的网关未绑定家庭无法进行添加");
        }
        if (StringUtils.isEmpty(deviceId)) {
            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "0FAC0207中央空调设备zigbeeMac未找到对应的ID");
        }
        List<String> addressList = (List<String>) map.get("acAddressList");

        //新的中央空调设备
        List<InfraredDeviceDO> infraredDevices = new ArrayList<>(16);

        //查询中央空调是否存在
        List<InfraredDeviceDO> list = list(Wrappers.<InfraredDeviceDO>lambdaQuery()
                .eq(InfraredDeviceDO::getDeviceId, deviceId));
        //如果红外设备中没有此类集合
        if (CollectionUtils.isEmpty(list)) {
            addressList.forEach(l -> {
                InfraredDeviceDO infraredDevice = new InfraredDeviceDO().saveAirCenter(deviceId, homeId, l);

                infraredDevices.add(infraredDevice);
            });
        }

        //如果红外设备中有此类集合
        if (CollectionUtils.isNotEmpty(list)) {
            addOrRemoveList(list, addressList, deviceId, homeId);
        }
        //如果没有默认直接保存
        boolean b = saveBatch(infraredDevices);
        if (b) {
            List<InfraredDeviceActions> deviceActions = new ArrayList<>(7);

            infraredDevices.forEach(inf -> {
                AcInfraredAction acInfraredAction = new AcInfraredAction().saveDefaultInfraredAction(inf.getCentralAcCode());
                String acInfActionStr = com.alibaba.fastjson.JSONObject.toJSONString(acInfraredAction);
                InfraredDeviceActions infraredDeviceActions = new InfraredDeviceActions().saveInfraredAction(inf.getId(), "acInfraredAction", acInfActionStr);
                deviceActions.add(infraredDeviceActions);
            });
            infraredDeviceActionsService.saveBatch(deviceActions);
        }
    }

    /**
     * 修改空调数据库状态信息
     *
     * @param deviceMac
     * @param gatewayMac
     * @param map
     */
    @Override
    public void updateAc(String deviceMac, String gatewayMac, Map<String, Object> map) {

        String deviceId = deviceDao.selectDeviceIdByMac(deviceMac);
        if (StringUtils.isEmpty(deviceId)) {
            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "0FAC0207中央空调设备zigbeeMac未找到对应的ID");
        }
        //map转化为对象
        JSONObject jsonObject2 = JSONObject.fromObject(map);
        AcInfraredAction acInfraredAction = (AcInfraredAction) JSONObject.toBean(jsonObject2, AcInfraredAction.class);

        //查询对应的红外设备
        InfraredDeviceDO infraredDevice = getOne(Wrappers.<InfraredDeviceDO>lambdaQuery().eq(InfraredDeviceDO::getDeviceId, deviceId)
                .eq(InfraredDeviceDO::getCentralAcCode, acInfraredAction.getAcAddress()));
        if (infraredDevice == null) {
            return;
        }
        String id = infraredDevice.getId();
        String acInfActionStr = com.alibaba.fastjson.JSONObject.toJSONString(acInfraredAction);
        InfraredDeviceActions infraredDeviceActions = new InfraredDeviceActions().saveInfraredAction(id,
                "acInfraredAction", acInfActionStr);

        infraredDeviceActionsService.update(infraredDeviceActions, Wrappers.<InfraredDeviceActions>lambdaQuery()
                .eq(InfraredDeviceActions::getInfraredDeviceId, id));

    }


    /**
     * 用于判断数据是否有重复，如果老数据新数据一致，不进行任何操作。
     * 如果老数据多于新数据，则删除多于的老数据，如果老数据少于新数据，就添加信息数据
     *
     * @param list
     * @param addressList
     * @param deviceId
     * @param homeId
     * @return
     */
    private List<InfraredDeviceDO> addOrRemoveList(List<InfraredDeviceDO> list, List<String> addressList, String deviceId, String homeId) {
        List<InfraredDeviceDO> infraredDevices = new ArrayList<>(16);
        //此循环的意思是先进行一遍新老判断如果不一样先把老的先删除掉
        list.forEach(old -> {
            final Boolean[] isDel = {true};
            addressList.forEach(l -> {
                if (old.getCentralAcCode().equals(l)) {
                    isDel[0] = false;
                }
            });
            if (isDel[0]) {
                removeById(old.getId());
            }
        });
        addressList.forEach(l -> {
            final Boolean[] isSave = {true};
            list.forEach(old -> {
                if (l.equals(old.getCentralAcCode())) {
                    isSave[0] = false;
                }
            });
            if (isSave[0]) {
                InfraredDeviceDO infraredDevice = new InfraredDeviceDO().saveAirCenter(deviceId, homeId, l);
                infraredDevices.add(infraredDevice);
            }
        });
        return infraredDevices;
    }
}